package cn.jiyun.hashMap_1_24; /**
 * @作者 Mr meng
 * @日期 2022/1/24
 * James Gosling 保佑：没有bug;
 * Linus Benedict Torvalds 保佑：没有bug;
 */

import java.util.LinkedList;

/**
 * 自定义的Hashmap
 */

public class MyHashMap implements MyMap{

    //数组的大小
    private int size;


    //用来存放LinkedList的数组（数组的下标用key所对应的hash值进行相应的计算而得到）

    private LinkedList<Entry>[] arr;

    /**?
     * 无参构造器，默认初始化数组为16，事实上，这里数组的初始化大小只要求大于0就行，
     * 过大会占用太多内存，过小则会影响
     * 查询的性能，因此这里根据参照源码，使其初始化大小为16，（jdk源码根据负载均衡会重新改表数组的大小，
     * 这里自己写实现简单）
     */
    private MyHashMap(){
        //默认初始化数组为16
        this(16);
    }

    /**
     *有参构造器
     * @param initialCapacity
     */
    public MyHashMap(int initialCapacity)
    {
        if (initialCapacity<=0)
        {
            throw new IllegalArgumentException();
        }
        else {
            this.arr=new LinkedList[initialCapacity];
        }
    }


    @Override
    public int size() {
        return size;
    }

    @Override
    public void put(Object key, Object value) {
        Entry entry = new Entry(key, value);
        int index=getIndex(key);
        if (arr[index]==null)
        {
            LinkedList<Entry> list = new LinkedList<>();
            list.add(entry);
            arr[index] = list;
            size++;
        }
        else {
            //判断key是否重复
            for (int i = 0; i < arr[index].size(); i++) {
                //如果重复的话就将集合中的key的值替换掉value值
                if (arr[index].get(i).getKey().equals(key))
                {
                    arr[index].get(i).value=value;
                    return;
                }
            }
        }
        arr[index].add(entry);
        size++;

    }

    private int getIndex(Object key)
    {
        return key.hashCode()%arr.length;
    }

    @Override
    public Object get(Object key) {
        int index = getIndex(key);
        //获得改索引处存放的链表
        LinkedList<Entry> list=arr[index];

        int i=getIndexOfNode(key,list);
        if (i!=-1)
        {
            return list.get(i).value;
        }
        return null;
    }

    /**
     * 根据key的hash值然后通过计算得到数组索引
     *  算法为：hash值除以arr数组的长度（这样保证了得到的数组索引是有效的）
     * @param key
     * @param list
     * @return
     */
    private int getIndexOfNode(Object key, LinkedList<Entry> list) {
        if (list!=null)
        {
            for (int i = 0; i < list.size(); i++) {
                if (list.get(i).key.equals(key))
                {
                    return i;
                }
            }
        }
        return -1;
    }

    @Override
    public boolean isEmpty() {
        return size==0;
    }

    @Override
    public void remove(Object key) {
        int index = getIndex(key);
        LinkedList<Entry> list=arr[index];
        int i = getIndexOfNode(key, list);
        if (i!=-1)
        {
            list.remove(i);
        }
    }

    @Override
    public boolean containsKey(Object key) {
        int index = getIndex(key);
        return getIndexOfNode(key,arr[index])!=-1;
    }

    @Override
    public boolean containValue(Object value) {
        for (int i = 0; i < arr.length; i++) {
            if (arr[i]!=null)
            {
                for (int j = 0; j < arr[i].size(); j++) {
                    if (arr[i].get(j).value.equals(value)){
                        return true;
                    }
                }
            }
        }
        return false;
    }
}
